module qtrt

import ffi

[ref_only]
struct GCRef {
    pub mut:
    cthis voidptr // non gc ptr, because of need call c++ destructor
}
pub struct CObject {
    pub mut:
    cthis voidptr
    objref &GCRef = voidptr(0) // gc ptr
    // let big enough to return sret
    pad1 u64
    pad2 u64
    pad3 u64
}

pub fn (cobj CObject) get_cthis() voidptr { return cobj.cthis }
pub fn (cobj CObject) set_cthis(cthis voidptr) {
    // mut cobj2 := cobj
    // cobj2.cthis = cthis
}

[no_inline]
pub fn newCObjectFromptr(cthis voidptr) CObject {
    return CObject{cthis, &GCRef{cthis}, 0, 0, 0}
}
pub fn (dummy CObject) Fromptr(cthis voidptr) CObject {
    return newCObjectFromptr(cthis)
}
pub fn (ptr CObject) toCObject() CObject { return ptr }

pub interface CObjectITF {
    get_cthis() voidptr
    toCObject() CObject
}

pub type CObjectITFx = voidptr | CObject
pub fn (this CObjectITFx) get_cthis() voidptr {
    mut cthis := voidptr(0)
    match this {
        voidptr { cthis = this}
        CObject { cthis = this.get_cthis()}
    }
    return cthis
}

// !!!!!
fn hotfix_interface_name_table(sender CObjectITF) {
    this := CObject{}
    hotfix_interface_name_table(this)
}

pub fn connect0(sender CObjectITF, signal string, fnptr voidptr) {
    cthis := sender.get_cthis()
    connect1(cthis, signal, fnptr)
}

pub fn connect1(sender voidptr, signal string, fnptr voidptr) {
    exist1 := qtconn_exist(sender, signal)
    mut conobj := &Qtconn{}
    if exist1 {
        // conobj = qtconn_get(sender, signal)
        // how
    }else {
        signal2 := qsignal(signal)
        conobj = qtconn_put(sender, signal2, fnptr)
        argtys := get_signal_argtys(sender, signal)
        get_signal_argtys(sender, signal)
        sobj := qdynslot_object_new(signal2, argtys, sender)
        qdynslot_object_connect_switch(sender, signal2, sobj, true)
    }
    // signal := "2clicked(bool)"
    // sobj := qtrt.qdynslot_object_new(signal, 456)
    // defer { qtrt.qdynslot_object_delete(sobj) }
    // println("${btn.cobject} ${sobj}")
    // qtrt.qdynslot_object_connect_switch(btn.cobject, signal, sobj, true)
}

type ConnectRaw = fn (voidptr, byteptr, voidptr, byteptr, int) voidptr

pub fn connectqq_impl(sender CObject, signal string, recver CObject, member string) {
    s := sender.get_cthis()
    r := recver.get_cthis()
    connect_raw(s, signal, r, member)
}

pub fn connect_raw(sender voidptr, signal string, recver voidptr, member string) {
    mut fnobj := ConnectRaw(0)
    fnobj = sym_qtfunc6(0, "_ZN7QObject7connectEPKS_PKcS1_S3_N2Qt14ConnectionTypeE")
    arg4 := 2 // Qt::QueuedConnection	2
    rv := fnobj(sender, signal.str, recver, member.str, arg4)

    qtconnection_dtor(rv)
}

type T_ZN11QMetaObject10ConnectionD2Ev = fn(voidptr)
pub fn qtconnection_dtor(cthis voidptr) {
    mut fnobj := T_ZN11QMetaObject10ConnectionD2Ev(0)
    fnobj = sym_qtfunc6(0, "_ZN11QMetaObject10ConnectionD2Ev")
    fnobj(cthis)
}

type T_QDynSlotObject_new = fn(voidptr, byteptr, int, voidptr, voidptr) voidptr

//fn C.memcpy(voidptr, voidptr, int) voidptr
pub fn qdynslot_object_new(signame string, argtys []int, cbptr voidptr) voidptr {
    signame_ := cstrdup(signame)
    fnptr_ := callback_all_qdynslot_object
    cbptr_ := cbptr
    argc := argtys.len
    // argtys_ := argtys.data
    // move argtys.data owner
    argtys_ := v_calloc((argtys.len+1)*argtys.element_size)
    if argtys.len > 0 {
        cmemcpy(argtys_, argtys.data, (argtys.len+1)*argtys.element_size)
    }

    mut fnobj := T_QDynSlotObject_new(0)
    fnobj = sym_cfunc6(0, "QDynSlotObject_new")
    rv := fnobj(fnptr_, signame_, argc, argtys_, cbptr_)
    return rv
}

pub type TCppDtor = fn(voidptr)
pub fn qdynslot_object_delete(cthis voidptr) {
    mut fnobj := TCppDtor(0)
    fnobj = sym_cfunc6(0, "QDynSlotObject_delete")
    fnobj(cthis)
}

type T_QDynSlotObject_connect_switch = fn(voidptr, byteptr, voidptr, int)

pub fn qdynslot_object_connect_switch(src voidptr, signature string, me voidptr, on bool) {
    mut fnobj := T_QDynSlotObject_connect_switch(0)
    fnobj = sym_cfunc6(0, "QDynSlotObject_connect_switch")
    fnobj(src, signature.str, me, ifelse<int>(on, 1, 0))
}

type T_QDynSlotObject_set_debug = fn(int)
pub fn qdynslot_object_set_debug(dbg bool) {
    mut fnobj := T_QDynSlotObject_set_debug(0)
    fnobj = sym_cfunc6(0, "QDynSlotObject_set_debug")
    fnobj(ifelse<int>(dbg, 1, 0))
}

type T_QObject_get_meta_signature_by_name = fn(voidptr, byteptr) byteptr
pub fn qobject_get_meta_signature_by_name(qobj voidptr, name string) string {
    mut fnobj := T_QObject_get_meta_signature_by_name(0)
    fnobj = sym_cfunc6(0, "QObject_get_meta_signature_by_name")
    rv := fnobj(qobj, name.str)
    return tos2(rv)
}

